#ifndef PARALLELFWD3_H_
#define PARALLELFWD3_H_

#include <map>
#include <set>
#include "../sff/siena/types.h"
#include "ompTypes.h"
#include <iostream>
#include "../../Common/Timer.h"
#include "../../Common/Consts.h"
#include <omp.h>
#include <string.h>
#include <algorithm>
#include <vector>

using namespace std;
using namespace siena;

class ParallelFwd3 {
 public:

  /**
   * Constructor
   */
  ParallelFwd3();

  /**
   * Destructor
   */
  virtual ~ParallelFwd3();

  /**
   * Config an interface by setting its predicate (the set of its filters)
   */
  void ifConfig(int interfaceId, set<OMPFilter *> &filters);

  /**
   * Call this after all interfaces have been set
   */
  void consolidate();

  /**
   * Processes the message included into the outbox.
   * Stores the set of matching interfaces ids inside the outbox.
   */
  void processMessage(OMPOutbox *outbox);

  /**
   * Returns the statistics about processing time distribution
   */
  void getStats(double *in, double *exec, double *res);

 private:

  map<int, set<OMPFilter *> > hostFilters;

  int numFilters;
  int numInterfaces;
  bool consolidated; 					       // True if the consolidate method has been called

  map<string_t, int> numConstraints;
  map<string_t, OMPType> nameType;             // Name -> type of constraints with that name
  map<string_t, BFilter *> nameConstrNames;
  map<string_t, void *> nameConstraints;
  OMPInput3 input; 					       // Pointer to the input

  bool *interfaces; 					       // Pointer to the array of interfaces
  OMPFilterInfo *filtersInfos;	                               // Filter -> filtersInfo
  unsigned short *filtersCount; 			       // Filter -> number of constraints satisfied

  double inputTime;
  double execTime;
  double resultsTime;

  inline bool prefix(char *s1, char *s2);
  inline bool substr(char *s1, char *s2);

  inline void evalConstraint(int constraintIndex, int attrId, BFilter inputBF, std::vector<float>& windowsList, int& ns, int& lastNs);
  inline BFilter makeInput(OMPMessage *message);
  inline void computeResults(BFilter bf, std::vector<float>& windowsList, int& ns, int& lastNs);
  inline void getMatchingInterfaces(set<int> &results);

  inline void buildIntConstraint(IntOMPConstraint3 *result, OMPConstraint &constraint, int filterId, BFilter bf);
  inline void buildStringConstraint(StringOMPConstraint3 *result, OMPConstraint &constraint, int filterId, BFilter bf);
};

#endif /* PARALLELFWD3_H_ */
